﻿namespace MicroCloud.Authorization
{
    #region "数据权限缓存基类"
    /// <summary>
    /// 数据权限缓存基类
    /// </summary>
    /// <typeparam name="TEntityInfo">实体信息类型</typeparam>
    /// <typeparam name="TEntityRole">实体角色类型</typeparam>
    /// <typeparam name="TRoleKey">角色编号类型</typeparam>
    /// <typeparam name="TEntityUser">实体用户类型</typeparam>
    /// <typeparam name="TUserKey">用户编号类型</typeparam>
    public abstract class DataAuthCacheBase<TEntityInfo, TEntityRole, TRoleKey, TEntityUser, TUserKey> : IDataAuthCache
        where TEntityInfo : class, IEntityInfo
        where TEntityRole : EntityRoleBase<TRoleKey>
        where TRoleKey : struct, IEquatable<TRoleKey>
        where TEntityUser : EntityUserBase<TUserKey>
        where TUserKey : struct, IEquatable<TUserKey>
    {
        //字段
        private readonly IServiceProvider _serviceProvider;
        private readonly IDistributedCache _cache;
        private readonly ILogger _logger;

        #region "构造函数"
        #region "初始化一个数据权限缓存基类的新实例"
        /// <summary>
        /// 初始化一个数据权限缓存基类 <see cref="DataAuthCacheBase{TEntityInfo, TEntityRole, TRoleKey, TEntityUser, TUserKey}"/> 的新实例
        /// </summary>
        /// <param name="serviceProvider">服务提供者</param>
        protected DataAuthCacheBase(IServiceProvider serviceProvider)
        {
            _serviceProvider = serviceProvider;
            _cache = serviceProvider.GetService<IDistributedCache>();
            _logger = serviceProvider.GetLogger(GetType());
        }
        #endregion

        #endregion

        #region "方法"
        #region "构建数据权限缓存"
        /// <summary>
        /// 构建数据权限缓存
        /// </summary>
        public virtual void BuildCaches()
        {
            using IServiceScope scope = _serviceProvider.CreateScope();
            var provider = scope.ServiceProvider;
            var entityInfoRepository = provider.GetService<IRepository<TEntityInfo, long>>();
            var entityInfos = entityInfoRepository.QueryAsNoTracking(null, false).Select(n => new { n.Id, n.TypeName }).ToList();

            // 数据用户
            UserRoleType userRoleType = UserRoleType.User;
            var entityUserRepository = provider.GetService<IRepository<TEntityUser, long>>();
            var entityUsers = entityUserRepository.QueryAsNoTracking(m => !m.IsLocked).Select(m => new
            {
                m.EntityId,
                Type = userRoleType,
                Name = m.UserId.ToString(),
                m.Operation,
                m.FilterGroupJson
            }).ToList().Select(s => new
            {
                s.Type,
                s.Name,
                EntityTypeFullName = entityInfos.Where(n => n.Id == s.EntityId).Select(n => n.TypeName).FirstOrDefault(),
                s.Operation,
                s.FilterGroupJson
            }).ToArray();

            foreach (var entityUser in entityUsers)
            {
                FilterGroup filterGroup = entityUser.FilterGroupJson.FromJsonString<FilterGroup>();
                if (filterGroup != null)
                {
                    string key = GetKey(userRoleType, entityUser.Name, entityUser.EntityTypeFullName, entityUser.Operation);
                    string name = GetName(userRoleType, entityUser.Name, entityUser.EntityTypeFullName, entityUser.Operation);

                    _cache.Set(key, filterGroup);
                    _logger.LogDebug("构建 {name} 数据权限规则缓存", name);
                }
            }
            // 数据角色
            userRoleType = UserRoleType.Role;
            var entityRoleRepository = provider.GetService<IRepository<TEntityRole, long>>();
            var entityRoles = entityRoleRepository.QueryAsNoTracking(m => !m.IsLocked).Select(m => new
            {
                m.EntityId,
                Type = userRoleType,
                Name = m.RoleId.ToString(),
                m.Operation,
                m.FilterGroupJson
            }).ToList().Select(s => new
            {
                s.Type,
                s.Name,
                EntityTypeFullName = entityInfos.Where(n => n.Id == s.EntityId).Select(n => n.TypeName).FirstOrDefault(),
                s.Operation,
                s.FilterGroupJson
            }).ToArray();
            //var entityRoles = entityRoleRepository.QueryAsNoTracking(m => !m.IsLocked).Select(m => new
            //{
            //    Type = userRoleType,
            //    Name = m.RoleId.ToString(),
            //    EntityTypeFullName = entityInfos.Where(n => n.Id == m.EntityId).Select(n => n.TypeName).FirstOrDefault(),
            //    m.Operation,
            //    m.FilterGroupJson
            //}).ToArray();

            foreach (var entityRole in entityRoles)
            {
                FilterGroup filterGroup = entityRole.FilterGroupJson.FromJsonString<FilterGroup>();
                if (filterGroup != null)
                {
                    string key = GetKey(userRoleType, entityRole.Name, entityRole.EntityTypeFullName, entityRole.Operation);
                    string name = GetName(userRoleType, entityRole.Name, entityRole.EntityTypeFullName, entityRole.Operation);

                    _cache.Set(key, filterGroup);
                    _logger.LogDebug("构建 {name} 数据权限规则缓存", name);
                }
            }
            _logger.LogInformation("构建 {length} 个数据权限过滤规则缓存", entityUsers.Length + entityRoles.Length);
        }
        #endregion
        #region "设置指定数据权限的缓存"
        /// <summary>
        /// 设置指定数据权限的缓存
        /// </summary>
        /// <param name="item">要设置的数据权限缓存项</param>
        public virtual void SetCache(DataAuthCacheItem item)
        {
            if (item?.FilterGroup != null)
            {
                string key = GetKey(item.Type, item.Name, item.EntityTypeFullName, item.Operation);
                string name = GetName(item.Type, item.Name, item.EntityTypeFullName, item.Operation);

                _cache.Set(key, item.FilterGroup);
                _logger.LogDebug("创建 {name} 数据权限规则缓存", name);
            }
        }
        #endregion
        #region "移除指定数据权限的缓存"
        /// <summary>
        /// 移除指定数据权限的缓存
        /// </summary>
        /// <param name="item">要移除的数据权限缓存项</param>
        public virtual void RemoveCache(DataAuthCacheItem item)
        {
            string key = GetKey(item.Type, item.Name, item.EntityTypeFullName, item.Operation);
            string name = GetName(item.Type, item.Name, item.EntityTypeFullName, item.Operation);

            _cache.Remove(key);
            _logger.LogDebug("移除 {name} 数据权限规则缓存", name);
        }
        #endregion
        #region "获取指定数据权限的过滤规则"
        /// <summary>
        /// 获取指定数据权限的过滤规则
        /// </summary>
        /// <param name="type">用户/角色类型</param>
        /// <param name="name">名称</param>
        /// <param name="entityTypeFullName">实体类型名称</param>
        /// <param name="operation">数据权限操作</param>
        /// <returns>数据过滤条件组</returns>
        public virtual FilterGroup GetFilterGroup(UserRoleType type, string name, string entityTypeFullName, DataAuthOperation operation)
        {
            string key = GetKey(type, name, entityTypeFullName, operation);
            return _cache.Get<FilterGroup>(key);
        }
        #endregion

        #endregion

        #region "私有静态方法"
        #region "获取缓存键"
        /// <summary>
        /// 获取缓存键
        /// </summary>
        /// <param name="type">用户/角色类型</param>
        /// <param name="name">名称</param>
        /// <param name="entityTypeFullName">实体类型全名</param>
        /// <param name="operation">数据权限操作</param>
        /// <returns>缓存键</returns>
        private static string GetKey(UserRoleType type, string name, string entityTypeFullName, DataAuthOperation operation)
        {
            return $"Auth:Data:{type}:{name}:{entityTypeFullName}:{operation}";
        }
        #endregion
        #region "获取缓存名称"
        /// <summary>
        /// 获取缓存名称
        /// </summary>
        /// <param name="type">用户/角色类型</param>
        /// <param name="name">名称</param>
        /// <param name="entityTypeFullName">实体类型全名</param>
        /// <param name="operation">数据权限操作</param>
        /// <returns>缓存名称</returns>
        private static string GetName(UserRoleType type, string name, string entityTypeFullName, DataAuthOperation operation)
        {
            return $"{type.ToDescription()}[{name}]和实体[{entityTypeFullName}]的{operation.ToDescription()}[{operation}]";
        }
        #endregion

        #endregion

    }
    #endregion

}
